﻿///////////////////////////////////////////////////////////////////////////////////////////////////
// AmiBroker Plug-in SDK | Copyright © 2010 by Koistya `Navin | http://code.google.com/p/amibroker/
// ------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at:
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.
///////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections.Specialized;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;

namespace AmiBrokerPlugin
{
    /// <summary>
    /// All public static methods of this class will be exported for use by AmiBroker
    /// </summary>
    public static partial class Plugin
    {
        #region Common Exported Functions

        /////////////////////////////////////////////////////////////////////////
        // COMMON EXPORTED FUNCTONS
        //
        // Each AmiBroker plug-in DLL must export the following functions:
        // 1. GetPluginInfo	- called when DLL is loaded
        // 2. Init - called when AFL engine is being initialized 
        // 3. Release - called when AFL engine is being closed
        /////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Called when DLL is loaded
        /// </summary>
        public static int GetPluginInfo(ref PluginInfo pluginInfo)
        {
            pluginInfo.Name = "Finam® data Plug-in";            // Plug-in Name
            pluginInfo.Vendor = "RiaGuy.com";                   // Plug-in Vendor
            pluginInfo.Type = PluginType.Data;                  // AFL, Data or an Optimizer
            pluginInfo.Version = 10001;                         // Plug-in version 1.0.0
            pluginInfo.IDCode = GetIDCode("FINM");              // Unique ID of the plugin
            pluginInfo.Certificate = 0;                         // Is it certified by AmiBroker?
            pluginInfo.MinAmiVersion = 529600;                  // 5.29.6
            pluginInfo.StructSize = Marshal.SizeOf(pluginInfo); // Just keep it

            return 1;
        }

        /// <summary>
        /// Called when AFL engine is being initialized
        /// </summary>
        public static int Init()
        {
            return 1;
        }

        /// <summary>
        /// Called when AFL engine is being closed
        /// </summary>
        public static int Release()
        {
            return 1;
        }

        #endregion

        #region Data Exported Functions

        /// <summary>
        /// GetQuotesEx function is functional equivalent fo GetQuotes but
        /// handles new Quotation format with 64 bit date/time stamp and floating point volume/open int
        /// and new Aux fields
        /// it also takes pointer to context that is reserved for future use (can be null)
        /// Called by AmiBroker 5.27 and above 
        /// </summary>
        unsafe public static int GetQuotesEx(string ticker, Periodicity periodicity, int lastValid, int size, Quotation* quotes, GQEContext* context)
        {
            Status = StatusCode.Wait;
            var result = GetQuotes(ticker, periodicity, lastValid, size, quotes);
            Status = StatusCode.OK;
            return result;
        }

        unsafe public delegate void* Alloc(uint size);

        ///// <summary>
        ///// GetExtra data is optional function for retrieving non-quotation data
        ///// </summary>
        public static AmiVar GetExtraData(string ticker, string name, int arraySize, Periodicity periodicity, Alloc alloc)
        {
            return new AmiVar();
        }

        /// <summary>
        /// Configure function is called when user presses "Configure" button in File->Database Settings
        /// </summary>
        public static int Configure(string path, IntPtr ptr)
        {
            //var GetStockQty = (InfoSite.GetStockQtyDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 4))), typeof(InfoSite.GetStockQtyDelegate));
            //var AddStock = (InfoSite.AddStockDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 8))), typeof(InfoSite.AddStockDelegate));
            var SetCategoryName = (InfoSite.SetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 12))), typeof(InfoSite.SetCategoryNameDelegate));
            //var GetCategoryName = (InfoSite.GetCategoryNameDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 16))), typeof(InfoSite.GetCategoryNameDelegate));
            //var SetIndustrySector = (InfoSite.SetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 20))), typeof(InfoSite.GetIndustrySectorDelegate));
            //var GetIndustrySector = (InfoSite.GetIndustrySectorDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 24))), typeof(InfoSite.SetIndustrySectorDelegate));
            var AddStockNew = (InfoSite.AddStockNewDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(Marshal.ReadInt32(new IntPtr(ptr.ToInt32() + 28))), typeof(InfoSite.AddStockNewDelegate));

            for (var i = 0; i < Markets.Count; i++)
            {
                SetCategoryName(0, i, Markets[i].Name);
            }
            for (var i = 0; i < Emitents.Count; i++)
            {
                var siPtr = AddStockNew(Emitents[i].Code);
                UpdateEmitent(siPtr);
            }
            return 1;
        }

        /// <summary>
        /// GetRecentInfo function is optional, used only by real-time plugins 
        /// </summary>
        public static RecentInfo GetRecentInfo(string ticker)
        {
            return new RecentInfo();
        }

        /// <summary>
        /// New API function, optional, only for RT plugins
        /// </summary>
        public static int IsBackfillComplete(string ticker)
        {
            return 1;
        }

        /// <summary>
        /// GetSymbolLimit function is optional, used only by real-time plugins
        /// </summary>
        public static int GetSymbolLimit()
        {
            return 1;
        }

        /// <summary>
        /// GetStatus function is optional, used mostly by few real-time plugins
        /// </summary>
        public static int GetStatus(IntPtr statusPtr)
        {
            switch (Status)
            {
                case StatusCode.OK:
                    SetStatus(statusPtr, StatusCode.OK, Color.LightGreen, "OK", "Плагин Finam® запущен");
                    break;
                case StatusCode.Wait:
                    SetStatus(statusPtr, StatusCode.Wait, Color.LightBlue, "Wait", "Подождите секунду...");
                    break;
                case StatusCode.Error:
                    SetStatus(statusPtr, StatusCode.Error, Color.Red, "Err", "Произошла ошибка");
                    break;
                default:
                    SetStatus(statusPtr, StatusCode.Unknown, Color.LightGray, "Oups", "Возможно, что-то не так");
                    break;
            }

            return 1;
        }

        /// <summary>
        /// SetTimeBase function is called when user is changing base time interval in File->Database Settings
        /// </summary>
        public static int SetTimeBase(int periodicity)
        {
            return periodicity >= (int)Periodicity.EndOfDay && periodicity <= (int)Periodicity.EndOfDay ? 1 : 0;
        }

        /// <summary>
        /// Notify function (optional) is called when database is loaded, unloaded
        /// settings are changed, or right mouse button in the plugin status area is clicked
        /// </summary>
        public static int Notify(ref PluginNotification notifyData)
        {
            if (MainWnd == IntPtr.Zero)
            {
                MainWnd = notifyData.MainWnd;
            }

            return 1;
        }

        #endregion

        #region Optimizer Plugin API

        /////////////////////////////////////////////////////////////////////////
        // OPTIMIZER PLUGIN API
        /////////////////////////////////////////////////////////////////////////

        //public static int OptimizerInit(ref OptimizeParams optimizeParams)
        //{
        //    return 1;
        //}

        //public delegate double EvaluateFuncDelegate(IntPtr param);

        //public static int OptimizerRun(ref OptimizeParams optimizeParams, EvaluateFuncDelegate evaluateFunc, IntPtr context)
        //{
        //    return 1;
        //}

        //public static int OptimizerFinalize(ref OptimizeParams optimizeParams)
        //{
        //    return 1;
        //}

        //public static int OptimizerSetOption(string param, AmiVar newValue)
        //{
        //    return 1;
        //}

        #endregion
    }
}
